﻿ 
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace Sky.FanQieDownload
{
    public class FanqieNovelDownloader
    {
        private readonly HttpClient _httpClient;
        private readonly string _baseUrl = "https://fanqie.hnxianxin.cn";
        private SemaphoreSlim _downloadSemaphore;
        private int _maxConcurrentDownloads = 5;
        private string _savePath = "Downloads";

        public FanqieNovelDownloader()
        {
            _downloadSemaphore = new SemaphoreSlim(_maxConcurrentDownloads, _maxConcurrentDownloads);

            _httpClient = new HttpClient();
            _httpClient.DefaultRequestHeaders.Add("x-sec-token", "8f79170487338570cdbb178e4653ed25943a6af05f3c29043782de49fc7a8fbd2446589412f746e396a05744cf546027bc63d7391b0e86ff3551c4d8e52ac1f97a2492bcc15dba6a9e2181084ed6e3f2a4d8a7e5aa419a705c5cffc8a93f5827fce376e3c3df14b8498405ba5f2630c0fa948894f4f7e5e26840f431f50396e9");
            _httpClient.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
            _httpClient.Timeout = TimeSpan.FromSeconds(30);

            // 创建保存目录
            Directory.CreateDirectory(_savePath);
        }

        public void SetConcurrentDownloads(int concurrent)
        {
            _maxConcurrentDownloads = concurrent;
            _downloadSemaphore = new SemaphoreSlim(_maxConcurrentDownloads, _maxConcurrentDownloads);
        }

        public void SetSavePath(string path)
        {
            _savePath = path;
            Directory.CreateDirectory(_savePath);
        }

        public async Task<DownloadResult> DownloadNovelAsync(string url, IProgress<DownloadProgress> progress = null)
        {
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
            var result = new DownloadResult { StartTime = DateTime.Now };

            try
            {
                // 提取bookId
                string bookId = GetBookId(url);
                if (string.IsNullOrEmpty(bookId))
                {
                    result.Success = false;
                    result.ErrorMessage = "无法从URL中提取书籍ID";
                    return result;
                }

                // 获取书籍信息
                var bookInfo = await GetBookInfoAsync(bookId);
                if (bookInfo == null)
                {
                    result.Success = false;
                    result.ErrorMessage = "获取书籍信息失败";
                    return result;
                }

                result.BookName = bookInfo.Title;

                // 获取章节列表
                var chapters = await GetChapterListAsync(bookId);
                if (chapters == null || chapters.Count == 0)
                {
                    result.Success = false;
                    result.ErrorMessage = "获取章节列表失败";
                    return result;
                }

                // 多线程下载所有章节内容
                var chapterContents = await DownloadChaptersParallelAsync(chapters, bookInfo.Title, progress);

                // 保存到文件
                await SaveToFileAsync(bookInfo, chapterContents);

                stopwatch.Stop();
                result.Success = true;
                result.TotalChapters = chapterContents.Count;
                result.ElapsedTime = stopwatch.Elapsed;
                result.EndTime = DateTime.Now;

                return result;
            }
            catch (Exception ex)
            {
                stopwatch.Stop();
                result.Success = false;
                result.ErrorMessage = ex.Message;
                result.ElapsedTime = stopwatch.Elapsed;
                return result;
            }
        }

        private int _completedCount = 0;

        private async Task<List<ChapterContent>> DownloadChaptersParallelAsync(
            List<ChapterItem> chapters, string bookName, IProgress<DownloadProgress> progress)
        {
            var tasks = new List<Task<ChapterContent>>();
            _completedCount = 0;
            int totalCount = chapters.Count;
            object lockObject = new object();

            foreach (var chapter in chapters)
            {
                tasks.Add(DownloadChapterWithSemaphoreAsync(chapter, progress, totalCount, lockObject));
            }

            var chapterContents = await Task.WhenAll(tasks);
            return chapterContents
                .Where(x => x != null && !string.IsNullOrEmpty(x.Content))
                .OrderBy(x => x.Number)
                .ToList();
        }

        private async Task<ChapterContent> DownloadChapterWithSemaphoreAsync(
            ChapterItem chapter, IProgress<DownloadProgress> progress, int totalCount, object lockObject)
        {
            await _downloadSemaphore.WaitAsync();
            try
            {
                var content = await GetSingleChapterAsync(chapter);
                int currentCount = Interlocked.Increment(ref _completedCount);

                progress?.Report(new DownloadProgress
                {
                    Current = currentCount,
                    Total = totalCount,
                    BookName = chapter.Title
                });

                return content;
            }
            catch (Exception)
            {
                return null;
            }
            finally
            {
                _downloadSemaphore.Release();
            }
        }

        // 以下方法与之前提供的C#代码相同（GetBookId, GetBookInfoAsync, GetChapterListAsync, GetSingleChapterAsync, CleanContentWithLinebreaks等）
        public string GetBookId(string url)
        {
            var matches = Regex.Matches(url, @"\d+");
            string maxMatch = null;
            foreach (Match match in matches)
            {
                if (maxMatch == null || match.Value.Length > maxMatch.Length)
                {
                    maxMatch = match.Value;
                }
            }
            return maxMatch;
        }

        public async Task<BookInfo> GetBookInfoAsync(string bookId)
        {
            string url = $"{_baseUrl}/detail?bookid={bookId}";

            for (int retry = 0; retry < 3; retry++)
            {
                try
                {
                    var response = await _httpClient.GetAsync(url);
                    if (response.IsSuccessStatusCode)
                    {
                        var json = await response.Content.ReadAsStringAsync();
                        var data = JObject.Parse(json)["data"];

                        if (data != null)
                        {
                            return new BookInfo
                            {
                                Title = data["original_book_name"]?.ToString(),
                                Author = data["author"]?.ToString(),
                                ChapterCount = data["content_chapter_number"]?.ToObject<int>() ?? 0,
                                Abstract = data["abstract"]?.ToString(),
                                BookId = bookId
                            };
                        }
                    }
                }
                catch
                {
                    if (retry == 2) throw;
                    await Task.Delay(1000);
                }
            }
            return null;
        }

        public async Task<List<ChapterItem>> GetChapterListAsync(string bookId)
        {
            string url = $"{_baseUrl}/chapter?bookid={bookId}";

            for (int retry = 0; retry < 3; retry++)
            {
                try
                {
                    var response = await _httpClient.GetAsync(url);
                    if (response.IsSuccessStatusCode)
                    {
                        var json = await response.Content.ReadAsStringAsync();
                        var data = JObject.Parse(json)["data"];
                        var itemDataList = data?["item_data_list"];

                        if (itemDataList != null)
                        {
                            var chapters = new List<ChapterItem>();
                            int chapterNum = 1;

                            foreach (var item in itemDataList)
                            {
                                chapters.Add(new ChapterItem
                                {
                                    Number = chapterNum,
                                    ItemId = item["item_id"]?.ToString(),
                                    Title = item["title"]?.ToString()
                                });
                                chapterNum++;
                            }
                            return chapters;
                        }
                    }
                }
                catch
                {
                    if (retry == 2) throw;
                    await Task.Delay(1000);
                }
            }
            return null;
        }

        private async Task<ChapterContent> GetSingleChapterAsync(ChapterItem chapter)
        {
            string url = $"{_baseUrl}/content?item_id={chapter.ItemId}";

            for (int retry = 0; retry < 3; retry++)
            {
                try
                {
                    var response = await _httpClient.GetAsync(url);
                    if (response.IsSuccessStatusCode)
                    {
                        var json = await response.Content.ReadAsStringAsync();
                        var content = JObject.Parse(json)["content"]?.ToString();

                        if (!string.IsNullOrEmpty(content))
                        {
                            return new ChapterContent
                            {
                                Number = chapter.Number,
                                Content = CleanContentWithLinebreaks(content),
                                Title = chapter.Title
                            };
                        }
                    }
                }
                catch
                {
                    if (retry == 2) throw;
                    await Task.Delay(500);
                }
            }
            return null;
        }

        private string CleanContentWithLinebreaks(string rawContent)
        {
            string decodedContent = System.Web.HttpUtility.HtmlDecode(rawContent);
            string paragraphContent = Regex.Replace(decodedContent, @"</p>", "\n");
            paragraphContent = Regex.Replace(paragraphContent, @"<p[^>]*>", "");
            string noTagContent = Regex.Replace(paragraphContent, @"<[^>]+>", "", RegexOptions.Singleline);
            string cleanText = Regex.Replace(noTagContent, @"[^\u4e00-\u9fa5a-zA-Z0-9\s，。！？；""''（）【】\n\t]", "");
            cleanText = Regex.Replace(cleanText, @"^\s+|\s+$", "", RegexOptions.Multiline);
            cleanText = Regex.Replace(cleanText, @"[ \t]+", " ");
            cleanText = Regex.Replace(cleanText, @"\n+", "\n").Trim();
            return cleanText;
        }

        private async Task SaveToFileAsync(BookInfo bookInfo, List<ChapterContent> chapters)
        {
            string safeTitle = string.Join("_", bookInfo.Title.Split(Path.GetInvalidFileNameChars()));
            string fileName = Path.Combine(_savePath, $"{safeTitle}.txt");

            using (var writer = new StreamWriter(fileName, false, Encoding.UTF8))
            {
                await writer.WriteLineAsync($"书名：{bookInfo.Title}");
                await writer.WriteLineAsync($"作者：{bookInfo.Author}");
                await writer.WriteLineAsync($"简介：{bookInfo.Abstract}");
                await writer.WriteLineAsync($"章节数：{chapters.Count}");
                await writer.WriteLineAsync(new string('=', 50));
                await writer.WriteLineAsync();

                foreach (var chapter in chapters)
                {
                    if (chapter != null && !string.IsNullOrEmpty(chapter.Content))
                    {
                        await writer.WriteLineAsync($"第{chapter.Number}章 {chapter.Title}");
                        await writer.WriteLineAsync();
                        await writer.WriteLineAsync(chapter.Content);
                        await writer.WriteLineAsync();
                        await writer.WriteLineAsync(new string('=', 30));
                        await writer.WriteLineAsync();
                    }
                }
            }
        }
    }

    // 数据模型类
    public class BookInfo
    {
        public string BookId { get; set; }
        public string Title { get; set; }
        public string Author { get; set; }
        public int ChapterCount { get; set; }
        public string Abstract { get; set; }
    }

    public class ChapterItem
    {
        public int Number { get; set; }
        public string ItemId { get; set; }
        public string Title { get; set; }
    }

    public class ChapterContent
    {
        public int Number { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
    }

    public class DownloadProgress
    {
        public int Current { get; set; }
        public int Total { get; set; }
        public string BookName { get; set; }
        public double Percentage => Total > 0 ? (double)Current / Total * 100 : 0;
    }

    public class DownloadResult
    {
        public bool Success { get; set; }
        public string BookName { get; set; }
        public int TotalChapters { get; set; }
        public TimeSpan ElapsedTime { get; set; }
        public DateTime StartTime { get; set; }
        public DateTime EndTime { get; set; }
        public string ErrorMessage { get; set; }
    }
}